import Designer from '@/index';
import classes from '@/class';
import Stage from '@/class/stage';
import { eventsSymbol } from '@/class/eventEmitter';
import { getType, isNumber, log, precision, uuid } from '@/utils';

/**
 * 节点数据转 JSON
 * @param {*} node
 * @returns
 */
export function toJSON(node) {
  if (node.className === 'Stage' && node.abortController) throw new Error('画布 Stage 请使用 toSchema 方法转JSON！');
  return JSON.stringify(node, (key, value) => {
    // 忽略监听事件
    if (key === 'events' && value?.[eventsSymbol]) return;
    // 忽略图片元素
    if (key === 'image' && getType(value) === 'HTMLImageElement') return;
    // // 父节点保存 id
    if (key === 'parent' && Designer.hasOwnProperty(value?.className)) return value?.id;
    // 控制数字精度
    if (isNumber(value)) return precision(value);
    return value;
  });
}

/**
 * 根据 JSON Schema 数据创建节点对象
 * @param {string|*} schema
 * @param {*} overrideConfig
 * @param {boolean} isClone
 * @returns
 */
export function create(schema, overrideConfig, isClone = false) {
  if (getType(schema) === 'String') schema = JSON.parse(schema);
  function generateNodes(config) {
    if (!classes[config?.className]) {
      log.warn(`不存在节点类：${config.className}`, config);
      return null;
    }
    // 节点克隆时使用新 id
    const instance = new classes[config.className]({ ...config, id: isClone ? uuid() : config.id });
    if (config.nodes) {
      config.nodes.forEach((node) => generateNodes({ ...node, parent: instance }));
      instance.update?.();
    }
    return instance;
  }
  return generateNodes({ ...schema, ...overrideConfig });
}

/**
 * 根据 JSON Schema 数据创建画布节点
 * @param {string|*} schema
 * @param {string|Element} container
 * @param {*} overrideConfig
 * @returns {Stage}
 */
export function createStage(schema, container, overrideConfig) {
  if (getType(schema) === 'String') schema = JSON.parse(schema);
  const stage = create(schema, { container, ...overrideConfig });
  const { selectedNodes, selectedEdges, depthOperation, lastTopGroup, edges, transformer } = schema;
  const { allNodesMap } = stage;
  if (getType(selectedNodes) === 'Array') stage.selectedNodes = selectedNodes.map((id) => allNodesMap[id]);
  if (getType(selectedEdges) === 'Array') stage.selectedEdges = selectedEdges;
  if (getType(depthOperation) === 'Boolean') stage.depthOperation = depthOperation;
  if (getType(lastTopGroup) === 'String') stage.lastTopGroup = allNodesMap[lastTopGroup];
  if (getType(edges) === 'Array') stage.edges = edges;
  // 转换器状态恢复
  if (getType(transformer) === 'Object') {
    stage.transformer.recover({ ...transformer, nodes: transformer.nodes.map((id) => allNodesMap[id]) });
  }
  setTimeout(() => {
    stage.emit('select', stage.selectedNodes, 'createStage');
    stage.emit('edgeSelect', stage.findEdge(stage.selectedEdges), 'createStage');
  });
  // 替换初始历史状态
  stage.history[0] = stage.toSchema();
  return stage;
}

/**
 * 节点克隆
 * @param {*} node
 * @param {*} overrideConfig
 * @returns
 */
export function clone(node, overrideConfig) {
  if (node.className === 'Stage') throw new Error('无法克隆 Stage 节点！');
  const newNode = create(JSON.parse(toJSON(node)), overrideConfig, true);
  (newNode.x += 10), (newNode.y += 10); // 克隆节点位置偏移
  return newNode;
}

/**
 * 注册节点
 */
export function register(Node) {
  let instance = new Node();
  if (!instance.className) throw new Error('注册节点出错！节点未指定 className 属性。');
  if (Designer.hasOwnProperty(instance.className)) throw new Error('注册节点出错！节点类名已存在。');
  Designer[instance.className] = Node;
  instance = null;
}

// 主题色
export const theme = '#0053FF';
// 辅助线颜色
export const guidesColor = '#F24822';
// 节点轮廓线宽
export const outlineLineWidth = 1;
// 默认字体 fontFamily
export const defaultFontFamily = 'arial,sans-serif';
